if (!dojo._hasResource["dojo.dnd.Moveable"]) { //_hasResource checks added by build. Do not use _hasResource directly in your code.
    dojo._hasResource["dojo.dnd.Moveable"] = true;
    dojo.provide("dojo.dnd.Moveable");

    dojo.require("dojo.dnd.Mover");

    dojo.declare("dojo.dnd.Moveable", null, {
        // object attributes (for markup)
        handle: "",
        delay: 0,
        skip: false,

        constructor: function(node, params) {
            // summary: an object, which makes a node moveable
            // node: Node: a node (or node's id) to be moved
            // params: Object: an optional object with additional parameters;
            //	following parameters are recognized:
            //		handle: Node: a node (or node's id), which is used as a mouse handle
            //			if omitted, the node itself is used as a handle
            //		delay: Number: delay move by this number of pixels
            //		skip: Boolean: skip move of form elements
            //		mover: Object: a constructor of custom Mover
            this.node = dojo.byId(node);
            if (!params) {
                params = {};
            }
            this.handle = params.handle ? dojo.byId(params.handle) : null;
            if (!this.handle) {
                this.handle = this.node;
            }
            this.delay = params.delay > 0 ? params.delay : 0;
            this.skip = params.skip;
            this.mover = params.mover ? params.mover : dojo.dnd.Mover;
            this.events = [
                dojo.connect(this.handle, "onmousedown", this, "onMouseDown"),
                // cancel text selection and text dragging
                dojo.connect(this.handle, "ondragstart", this, "onSelectStart"),
                dojo.connect(this.handle, "onselectstart", this, "onSelectStart")
            ];
        },

        // markup methods
        markupFactory: function(params, node) {
            return new dojo.dnd.Moveable(node, params);
        },

        // methods
        destroy: function() {
            // summary: stops watching for possible move, deletes all references, so the object can be garbage-collected
            dojo.forEach(this.events, dojo.disconnect);
            this.events = this.node = this.handle = null;
        },

        // mouse event processors
        onMouseDown: function(e) {
            // summary: event processor for onmousedown, creates a Mover for the node
            // e: Event: mouse event
            if (this.skip && dojo.dnd.isFormElement(e)) {
                return;
            }
            if (this.delay) {
                this.events.push(dojo.connect(this.handle, "onmousemove", this, "onMouseMove"));
                this.events.push(dojo.connect(this.handle, "onmouseup", this, "onMouseUp"));
                this._lastX = e.pageX;
                this._lastY = e.pageY;
            } else {
                new this.mover(this.node, e, this);
            }
            dojo.stopEvent(e);
        },
        onMouseMove: function(e) {
            // summary: event processor for onmousemove, used only for delayed drags
            // e: Event: mouse event
            if (Math.abs(e.pageX - this._lastX) > this.delay ||
                Math.abs(e.pageY - this._lastY) > this.delay) {
                this.onMouseUp(e);
                new this.mover(this.node, e, this);
            }
            dojo.stopEvent(e);
        },
        onMouseUp: function(e) {
            // summary: event processor for onmouseup, used only for delayed delayed drags
            // e: Event: mouse event
            dojo.disconnect(this.events.pop());
            dojo.disconnect(this.events.pop());
        },
        onSelectStart: function(e) {
            // summary: event processor for onselectevent and ondragevent
            // e: Event: mouse event
            if (!this.skip || !dojo.dnd.isFormElement(e)) {
                dojo.stopEvent(e);
            }
        },

        // local events
        onMoveStart: function(/* dojo.dnd.Mover */ mover) {
            // summary: called before every move operation
            dojo.publish("/dnd/move/start", [mover]);
            dojo.addClass(dojo.body(), "dojoMove");
            dojo.addClass(this.node, "dojoMoveItem");
        },
        onMoveStop: function(/* dojo.dnd.Mover */ mover) {
            // summary: called after every move operation
            dojo.publish("/dnd/move/stop", [mover]);
            dojo.removeClass(dojo.body(), "dojoMove");
            dojo.removeClass(this.node, "dojoMoveItem");
        },
        onFirstMove: function(/* dojo.dnd.Mover */ mover) {
            // summary: called during the very first move notification,
            //	can be used to initialize coordinates, can be overwritten.

            // default implementation does nothing
        },
        onMove: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop) {
            // summary: called during every move notification,
            //	should actually move the node, can be overwritten.
            this.onMoving(mover, leftTop);
            var s = mover.node.style;
            s.left = leftTop.l + "px";
            s.top = leftTop.t + "px";
            this.onMoved(mover, leftTop);
        },
        onMoving: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop) {
            // summary: called before every incremental move,
            //	can be overwritten.

            // default implementation does nothing
        },
        onMoved: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop) {
            // summary: called after every incremental move,
            //	can be overwritten.

            // default implementation does nothing
        }
    });

}
